//------------------------------------------------------------------------------
// The confidential and proprietary information contained in this file may
// only be used by a person authorised under and to the extent permitted
// by a subsisting licensing agreement from ARM Limited.
//
//            (C) COPYRIGHT 2008-2012 ARM Limited.
//                ALL RIGHTS RESERVED
//
// This entire notice must be reproduced on all copies of this file
// and copies of this file may only be made by a person if such person is
// permitted to do so under the terms of a subsisting license agreement
// from ARM Limited.
//------------------------------------------------------------------------------
// Version and Release Control Information:
//
// File Revision       : 130657
// File Date           :  2012-05-28 17:35:55 +0100 (Mon, 28 May 2012)
// Release Information : PL401-r0p1-00eac0
//------------------------------------------------------------------------------
// Purpose             : This module is responsible for demuxing the downsizer R 
//                       data channel, packing smaller RData beats into the 
//                       larger upstream data bus.
//                       This module lives in the IB Master Domain.
//                       This module will also mask the multiple rlasts produced
//                       by spliting transactions into a single rlast for the
//                       upstream transaction.
//                       It contains a single register for storing the data this 
//                       is so it can be used without an attached fifo. 
//                       (the V/R will attach directly to the AXI R channel)
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//
//  Config :
//           o  Outstanding Reads  = 1
//
//           o  Slave_if DataWidth = 64
//           o  Master_if DataWidth = 32
//
//------------------------------------------------------------------------------

module nic400_ib_dma_axi4_cpu_ib_downsize_rd_chan_ysyx_rv32
  (
  //rchannel Inputs
  rvalid_m,
  rdata_m,
  rlast_m,
  rid_m,
  rresp_m,
  
  rready_s,
 
  //rchannel Outputs
  rready_m,
  
  rvalid_s,
  rdata_s,
  rlast_s,
  rid_s,
  rresp_s,
  
  rbeats_s,
  

  arvalid_m,
  arready_m,

  //From the Archannel forward block
  archannel_data,
  archannel_valid,
  archannel_ready,
  
  arsize,
  araddr,
  arid,
  
  aclk, 
  aresetn
  );

`include "nic400_ib_dma_axi4_cpu_ib_defs_ysyx_rv32.v"
`include "Axi.v"

  //System
  input                   aclk;
  input                   aresetn;

  // To/From the Archannel forward block
  input                   archannel_valid;
  output                  archannel_ready;
  input [11:0]            archannel_data;

    
  output                  arvalid_m;
  input                   arready_m;
  
  input [2:0]             arsize;
  input [2:0]             araddr;
  input [3:0]             arid;

  
  //Slave Bus rchannel signals
  input                   rready_s;               

  output                  rvalid_s;
  output [63:0]           rdata_s;
  output [3:0]            rid_s;
  output [1:0]            rresp_s;
  output                  rlast_s;
  
  output [1:0]            rbeats_s;

  //Master Bus rchannel signals
  output                  rready_m;               

  input                   rvalid_m;
  input [31:0]            rdata_m;
  input [3:0]             rid_m;
  input [1:0]             rresp_m;
  input                   rlast_m;

   //------------------------------------------------------------------------
   // Wires
   //------------------------------------------------------------------------   
 
   wire                   match_bus; 
   wire                   hazard_bus;
   wire                   valid_bus;
   wire                   last_addr_match_bus;
   wire                   beat_complete_slice_bus;

   reg                    hazard_pointer;
   reg                    match_pointer;

   wire                   hazard;           //Hazard detected
   wire                   last_addr_match;  //Signal to move to next beat
   wire                   beat_complete_slice;           

   reg                    store;

   wire                   archannel_hndshk;
   wire                   rchannel_hndshk;

   wire                   push_slice;
   wire                   pop_slice;          //push and pop signals for the CAM Slices
   wire                   update;

   wire                   beat_complete;

   
   wire                   bypass;

   wire [1:0]             rbeats;
 
   wire                   rlast_m;
   wire [3:0]             rid_m;
   wire [1:0]             rresp_m;
   
   wire                   rlast_out;
   wire                   rlast_out_masked;
   
   wire [10:0]            ar_cam_data;
   
   wire [11:0]            ar_channel_data;

   wire                   cam_update;




   //These are signals output from the cam slices
    
  
   wire [1:0]             beat_number0;
       
   wire [1:0]             rresp_cam;
   wire                   mask_last;
   wire [31:0]            rdata_cam;
   
   
  
   wire [31:0]            rdata_cam0;
  
   wire [1:0]             rresp_cam0;
  
   wire                   mask_last0;
   
   wire [63:0]            rdata_out;
   wire [1:0]             rresp_out;
   
   wire                   fixed_dwnsize;   
   
   wire [3:0]                n_response;
   
   wire [2:0]             addr_mask;
   
   wire [3:0]                next_n_response_reg;
   wire                   n_response_reg_wr_en;
   wire                   slice_required;
    
    
    

   //------------------------------------------------------------------------
   // Regs
   //------------------------------------------------------------------------   

   reg [2:0]              downsize;

   reg [3:0]                 n_response_reg;

   //------------------------------------------------------------------------
   // Encode RFIFO data
   //------------------------------------------------------------------------   

   assign rid_s = rid_m;
   assign rdata_s = rdata_out;
   assign rresp_s = rresp_out;
   assign rlast_s = rlast_out_masked;
   
   assign rbeats_s = rbeats;
     


   //------------------------------------------------------------------------
   // Combine Signals from Cam Slices
   //------------------------------------------------------------------------   

   //Hazard
   assign hazard = hazard_bus;

   //Last
   assign last_addr_match = (last_addr_match_bus & match_bus);

   //Bypass
   assign beat_complete_slice = (beat_complete_slice_bus & match_bus);

   //Select beat_number values;
   assign rbeats = beat_number0;
   
   //Select rdata from CAM
   assign rdata_cam = rdata_cam0;
   
   //Select rresp_cam signal
   assign rresp_cam = rresp_cam0;
   
   //Select mask_last signal
   assign mask_last = mask_last0;

   

   //------------------------------------------------------------------------
   // Set rdata demux & RLAST generatation
   //------------------------------------------------------------------------ 

   assign rdata_out[63:32] = rdata_m;
    
   assign rdata_out[31:0] = rdata_cam[31:0];



   assign rlast_out = last_addr_match  && rlast_m;
   
   assign rlast_out_masked = rlast_out & ~mask_last;
   
   assign rresp_out = rresp_cam;
   
   //------------------------------------------------------------------------
   // Generate downsize mask from ASIZE of incoming axi slave trans
   //------------------------------------------------------------------------

   //downsize is thermometer encoded size mask
  always @(archannel_data)
    begin : downsize_mask_p
      case (archannel_data[2:0])
         `AXI_ASIZE_8    : downsize = {3{1'b0}};
         `AXI_ASIZE_16   : downsize = {{2{1'b0}},{1'b1}};
         `AXI_ASIZE_32   : downsize = {{1{1'b0}},{2'b11}};
         `AXI_ASIZE_64   : downsize = {{3'b111}};
         `AXI_ASIZE_128,
       `AXI_ASIZE_256,
       `AXI_ASIZE_512,
       `AXI_ASIZE_1024 : downsize = {3{1'b0}};    //Unused case arsize should never hit in normal operation
        default : downsize = 3'bx;
      endcase
    end
    
    
    assign ar_cam_data = {arid,araddr,arsize[1:0],fixed_dwnsize,bypass};
    
    assign ar_channel_data = {downsize,archannel_data[11:3]};
    

   //------------------------------------------------------------------------
   // Valid/Ready Generation for all signals
   //------------------------------------------------------------------------
   
   assign n_response = archannel_data[11:8];
   
   
   assign addr_mask = archannel_data[5:3];
   
   // The bypassed trans can be detected by comparing the incoming arsize
   // with the size of the outgoing transaction
   
   
    assign bypass = (archannel_data[2:0] == arsize[2:0]) & (~|n_response);

   
   // This single-bit mask is pushed into the appropriate CAM slice
   // along with the AR info allowing lasts from downsized fixed transactions 
   // to be suppressed.
   assign fixed_dwnsize = (|n_response) & (downsize[2]) & (~|addr_mask);
      
   
   //n response logic ... This is used to mask the first lasts during a fixed trans that 
   //has been downsized into multiple incr transactions;
   assign next_n_response_reg = n_response; 

   assign n_response_reg_wr_en =  (archannel_hndshk);


   always @(posedge aclk or negedge aresetn)
     begin : next_resp_seq
       if (!aresetn) 
          n_response_reg <= 4'b0;
      else if (n_response_reg_wr_en)
           n_response_reg <= next_n_response_reg;
   end // two_resp_seq

   //Archannel_ready is true when there is an empty slice (or about to be)
   assign arvalid_m = archannel_valid & ((~&valid_bus) | ~slice_required);
   assign archannel_ready = arready_m & ((~&valid_bus) | ~slice_required); 

   //Detect AR channel handshake 
   assign archannel_hndshk = archannel_ready && archannel_valid;

   //A slice is pushed when an AR channel handhake.
   //It is identifed by push and store signals
   assign slice_required = (~|n_response_reg) | ((downsize[2]) & (~|addr_mask));
   assign push_slice = archannel_hndshk & slice_required;
   
   //store decode Logic
   always @(valid_bus or match_bus)
     begin : store_decode
        if (!valid_bus)
           store = 1'b1;
        else
           store = match_bus;
      end // store_decode
      
   //Distribute the number of the Slice reporting a Hazard
   always @(hazard_bus)
     begin : hazard_num_distibution
       case (hazard_bus)
          1'b0 : hazard_pointer = 1'b0;
           1'd1 : hazard_pointer = 1'd0;
         default : hazard_pointer = 1'bx;
       endcase
     end
     
   //Distribute the number of the Slice reporting a Hazard
   always @(match_bus)
     begin : match_num_distibution
       case (match_bus)
          1'b0 : match_pointer = 1'b0;
           1'd1 : match_pointer = 1'd0;
         default : match_pointer = 1'bx;
       endcase
     end

   //Detect a complete beat
   assign beat_complete = (rlast_out | beat_complete_slice) && update;

   
   //rchannel_ready
   assign rready_m = (beat_complete | (~beat_complete_slice)) && rvalid_m;

   //RVALIDS is always true while there is valid data in the device
   assign rvalid_s = beat_complete_slice && rvalid_m;
   

   //Detect handshake on the Slave R Channel
   assign rchannel_hndshk = rvalid_s && rready_s;
      
   //The addr registers are updated on every handshake on the Rchannel
   assign update = rchannel_hndshk;
   
   //The address inrementer in the cam slice is updated on every incoming R hndshk
   assign cam_update = rvalid_m & rready_m;

   //The Selcted cam Slice is popped when an R Channel handsake with RLAST occurs
   assign pop_slice = update && rlast_out;

   //------------------------------------------------------------------------
   // CAM SLices 
   //------------------------------------------------------------------------   

    
     //Cam Slice number 0 //
     nic400_ib_dma_axi4_cpu_ib_downsize_rd_cam_slice_ysyx_rv32 u_downsize_rd_cam_slice_0
     (
         // global signals
        .aresetn              (aresetn),
        .aclk                 (aclk),

        // ID inputs (to all slices)
        .match_id              (rid_m),      

        //Control Signals
        .store                (store),
        .push_slice           (push_slice),
        .pop_slice            (pop_slice),
        .update               (cam_update),
        .match_pointer        (match_pointer),

        .archannel_data       (ar_channel_data),
        
        .ar_cam_data          (ar_cam_data),
        
        .rdata_m              (rdata_m),
        .rresp_m              (rresp_m),
        .rlast_m              (rlast_m),
         
        .hazard_in            (hazard),
        .hazard_pointer       (hazard_pointer),
   
        //Outputs
        .hazard               (hazard_bus),
        .match                (match_bus),
        .valid                (valid_bus),
        .last_addr_match      (last_addr_match_bus),
        .beat_complete        (beat_complete_slice_bus),
        .beat_number          (beat_number0),
        
        .rdata_cam            (rdata_cam0),
        
        .rresp_cam            (rresp_cam0),
        
        .mask_last            (mask_last0)
     );
     


`ifdef ARM_ASSERT_ON
//------------------------------------------------------------------------
// OVL Assertions 
//------------------------------------------------------------------------
// Include Standard OVL Defines
`include "std_ovl_defines.h"

   //------------------------------------------------------------------------
   // OVL_ASSERT: Check that only one Slice ever matches
   //------------------------------------------------------------------------
   // If more than one slot matches the hazard detection logic has gone wrong
   //------------------------------------------------------------------------

   // OVL_ASSERT_RTL
  assert_never_unknown #(0,1,"Rd Channel Slice match has gone wrong")
  ovl_single_ID_match
    (
     .clk              (aclk),
     .reset_n          (aresetn),
     .qualifier        (match_bus),
     .test_expr        (rchannel_hndshk)
     );
   // OVL_ASSERT_END

   //------------------------------------------------------------------------
   // OVL_ASSERT: Check that only one Slice ever reports a hazard
   //------------------------------------------------------------------------
   // If more than one slot matches the last detection logic has gone wrong
   //------------------------------------------------------------------------

   // OVL_ASSERT_RTL
  assert_never_unknown #(0,1,"Rd Channel Slice hazard has gone wrong")  
  ovl_single_hazard
    (
     .clk              (aclk),
     .reset_n          (aresetn),
     .qualifier        (hazard_bus),
     .test_expr        (archannel_hndshk)
     );
   // OVL_ASSERT_END


   //----------------------------------------------------------------------------
   // OVL_ASSERT: downsize_rd_chan has received an unsupported ARSIZE
   //----------------------------------------------------------------------------
   // This OVL assertion should fire whenever the read channel receives an 
   // unsupported ARSIZE.
   //----------------------------------------------------------------------------
   // OVL_ASSERT_RTL
     
     wire        arsize_out_range;
 
     assign      arsize_out_range = archannel_valid && (archannel_data[2:0] > `AXI_ASIZE_64);
                                                                                             
     wire        illegal_downsize;        // Illegal downsize signal

     // Signal an illegal total_bytes
     assign illegal_downsize =  (downsize == {3{1'b0}}) & arsize_out_range;

     // OVL Assertion
     assert_never #(`OVL_FATAL,
                    `OVL_ASSERT,
                    "Input archannel_data[2:0] to downsize calculation has gone out of legal range")
     ovl_downsize_illegal_asize
     (
       .clk        (aclk),
       .reset_n    (aresetn),
       .test_expr  (illegal_downsize)
     );
   // OVL_ASSERT_END


   //----------------------------------------------------------------------------
`endif

endmodule

`include "nic400_ib_dma_axi4_cpu_ib_undefs_ysyx_rv32.v"
`include "Axi_undefs.v"

